﻿namespace NetFx.SMIL.References
{
  using System;
  using System.Text;
  using System.Collections.Generic;

  /// <summary>
  /// 完全限定名。
  /// </summary>
  public class QualifiedIdentifier
  {
    #region Statics
    /// <summary>
    /// 空标识符。
    /// </summary>
    public static readonly QualifiedIdentifier EmptyIdentifier = new QualifiedIdentifier(NamespaceSeparator);
    /// <summary>
    /// 命名空间标识符分隔符。
    /// </summary>
    public const char NamespaceSeparator = '.';
    /// <summary>
    /// 嵌套类标识符分隔符。
    /// </summary>
    public const char NestingTypeSeparator = '+';
    /// <summary>
    /// 根据全名创建标识符。
    /// </summary>
    /// <param name="fullname">用标识符分割范围的全名。</param>
    /// <returns>全名对应的标识符。</returns>
    public static QualifiedIdentifier CreateIdentifierOf(char separator,string fullname)
    {

      return fullname != null ? CreateIdentifierNaturallyWith(
        separator,
        fullname.Split(separator)
        ) : new QualifiedIdentifier(separator);
    }
    /// <summary>
    /// 根据名称和父标识符创建标识符。
    /// </summary>
    /// <param name="name">标识符名称。</param>
    /// <param name="parent">父标识符名称。</param>
    /// <returns>对应的标识符。</returns>
    public static QualifiedIdentifier CreateIdentifierOf(char separator, string name, QualifiedIdentifier parent)
    {
      return new QualifiedIdentifier(separator,name, parent);
    }
    /// <summary>
    /// 根据范围列表创建标识符。
    /// </summary>
    /// <param name="scopes">范围列表（大范围在前，也就是下表较小）。</param>
    /// <returns>范围列表对应的标识符。</returns>
    public static QualifiedIdentifier CreateIdentifierWith(char separator, params string[] scopes)
    {
      if (scopes != null)
      {
        return new QualifiedIdentifier(separator,scopes);
      }
      else
      {
        return new QualifiedIdentifier(separator);
      }
    }
    /// <summary>
    /// 根据范围列表创建标识符。
    /// </summary>
    /// <param name="scopes">范围列表（大范围在前，也就是下表较小）。</param>
    /// <returns>范围列表对应的标识符。</returns>
    public static QualifiedIdentifier CreateIdentifierNaturallyWith(char separator, params string[] scopes)
    {
      if (scopes != null)
      {
        Array.Reverse(scopes); //反转范围列表，使得小名称在前。
        return CreateIdentifierWith(separator,scopes);
      }
      else
      {
        return new QualifiedIdentifier(separator);
      }
    }
    #endregion
    #region Fields
    protected char separator = NamespaceSeparator;
    protected string name = string.Empty;
    protected QualifiedIdentifier parent =null;
    #endregion
    #region Properties
    public virtual string Name
    {
      get
      {
        return this.name;
      }
    }
    public virtual char Separator
    {
      get
      {
        return this.separator;
      }
    }
    public virtual QualifiedIdentifier Parent
    {
      get
      {
        return this.parent;
      }
    }
    public virtual bool HasParent
    {
      get
      {
        return this.parent != null;
      }
    }
    public virtual string[] Scopes
    {
      get
      {
        List<string> scope = new List<string>();
        this.CollectScopes(scope);
        return scope.ToArray();
      }
    }
    public virtual string[] NaturalScopes
    {
      get
      {
        string[] scopes = this.Scopes;
        Array.Reverse(scopes);
        return scopes;
      }
    }
    public virtual bool NameExists
    {
      get
      {
        return !string.IsNullOrEmpty(this.ToString());
      }
    }
    #endregion
    #region Constructors
    /// <summary>
    /// 根据范围列表创建标识符。
    /// </summary>
    /// <param name="separator">分隔符。</param>
    /// <param name="scopes">范围列表（最小的名称在最前面）</param>
    public QualifiedIdentifier(char separator, params string[] scopes)
      : this(separator,scopes, 0)
    {
    }
    /// <summary>
    /// 根据范围列表创建标识符。
    /// </summary>
    /// <param name="separator">分隔符。</param>
    /// <param name="scopes">范围列表（最小的名称在最前面）</param>
    /// <param name="startIndex">起始下标。</param>
    protected QualifiedIdentifier(char separator, string[] scopes, int startIndex)
    {
      if (scopes != null && startIndex >= 0 && startIndex < scopes.Length)
      {
        this.separator = separator;
        this.name = scopes[startIndex++];
        this.parent =
          ((startIndex < scopes.Length) ? (new QualifiedIdentifier(separator,scopes, startIndex)) : null);
      }
    }
    /// <summary>
    /// 根据名称和父标识符创建标识符。
    /// </summary>
    /// <param name="separator">分隔符。</param>
    /// <param name="name">名称（建议不要为空）。</param>
    /// <param name="parent">父标识符（如果是根标识符，则可以为空）。</param>
    public QualifiedIdentifier(char separator, string name, QualifiedIdentifier parent)
    {
      this.separator = separator;
      this.name = name;
      this.parent = parent;
    }
    #endregion
    #region Methods
    public override string ToString()
    {
      string[] scope = this.NaturalScopes;

      StringBuilder longName = new StringBuilder();
      if (scope != null)
      {
        for (int i = 0; i < scope.Length; i++)
        {
          string name = scope[i];
          if (name == null)
          {
            //SHOULD NOT!
          }
          else
          {
            longName.Append(name);
            if (i > 0)
            {
              longName.Append(
                this.Separator
                );
            }
          }
        }
      }
      return longName.ToString();
    }
    public override bool Equals(object obj)
    {
      if (obj is QualifiedIdentifier)
      {
        return (obj as QualifiedIdentifier).ToString() == this.ToString();
      }
      return false;
    }
    public override int GetHashCode()
    {
      return this.ToString().GetHashCode();
    }
    public virtual QualifiedIdentifier Clone()
    {
      return new QualifiedIdentifier(this.separator, this.Scopes);
    }
    protected virtual void CollectScopes(List<string> scope)
    {
      scope.Add(this.Name);
      if (this.HasParent)
      {
        this.Parent.CollectScopes(scope);
      }
    }
    #endregion
  }
}
